﻿using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Casamiel.Application;
using Casamiel.Domain.Entity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Casamiel.Common;

namespace Casamiel.API.Infrastructure.Filters
{
    /// <summary>
    /// Booking check token attribute.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)]
    public class BookingCheckTokenAttribute : Attribute, IAsyncActionFilter
    {
        private readonly IMemberService _member;
        private readonly ICacheService _cacheService;
        private readonly CasamielSettings _settings;
        /// <summary>
        /// Initializes a new instance of the
        /// 
        /// </summary>
        /// <param name="memberService">Member service.</param>
        /// <param name="cacheService">Cache service.</param>
        /// <param name="settings">Settings.</param>
        public BookingCheckTokenAttribute(IMemberService memberService,
            ICacheService cacheService
            , IOptionsSnapshot<CasamielSettings> settings
           )
        {
            if (settings == null) {
                throw new ArgumentNullException(nameof(settings));
            }

            _member = memberService;
            _cacheService = cacheService;
            _settings = settings.Value;
        }
        /// <summary>
        /// Ons the action execution async.
        /// </summary>
        /// <returns>The action execution async.</returns>
        /// <param name="context">Context.</param>
        /// <param name="next">Next.</param>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (context == null) {
                throw new ArgumentNullException(nameof(context));
            }

            if (next == null) {
                throw new ArgumentNullException(nameof(next));
            }

            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("cssupersecret_secretke!miel"));
            var tokenValidationParameters = new TokenValidationParameters {
                // The signing key must match!
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,

                // Validate the JWT Issuer (iss) claim
                ValidateIssuer = true,
                ValidIssuer = "CasamielIssuer",

                // Validate the JWT Audience (aud) claim
                ValidateAudience = true,
                ValidAudience = "casamiel",

                // Validate the token expiry
                ValidateLifetime = true,

                // If you want to allow a certain amount of clock drift, set that here:
                ClockSkew = TimeSpan.Zero
            };
            var token = context.HttpContext.Request.Headers["u-token"];
            //var userAgent = string.IsNullOrEmpty(context.HttpContext.Request.Headers["User-Agent"].ToString()) ? context.HttpContext.Request.Headers["UserAgent"].ToString() : context.HttpContext.Request.Headers["User-Agent"].ToString();
            //int loginType = 4;// userAgent.Contains("CASAMIEL") ? 1 : 2;
            //if (userAgent.Contains("MicroMessenger"))
            //{
            //    loginType = 3;//微信端
            //}
            if (string.IsNullOrEmpty(token)) {
                context.Result = new JsonResult(new { code = -18, msg = "token无效" });
                return;
            }

            var handler = new JwtSecurityTokenHandler();
            ClaimsPrincipal principal = null;
            SecurityToken validToken = null;
            try {
                principal = handler.ValidateToken(token, tokenValidationParameters, out validToken);
            } catch (SecurityTokenSignatureKeyNotFoundException) {
                //Console.WriteLine(ex.Message);
                context.Result = new JsonResult(new { code = -18, msg = "token无效" });
                return;
            }
            catch(SecurityTokenExpiredException ex) {
                Console.WriteLine(ex.StackTrace);
                context.Result = new JsonResult(new { code = -14, msg = "登录凭证已过期，请重新登陆" });
                return;
            }
            catch(Exception e) {
                Console.WriteLine(e.StackTrace);
                context.Result = new JsonResult(new { code = -18, msg = "token无效" });
                return;
            }
            var validJwt = validToken as JwtSecurityToken;

            if (validJwt == null) {
                context.Result = new JsonResult(new { code = -18, msg = "token无效" });
                return;
            }
            JwtSecurityToken dtoken = handler.ReadJwtToken(token);
            var rsa = new RSAHelper(RSAType.RSA2, Encoding.UTF8, RSAHelper.privateKey, RSAHelper.publicKey);

            var exp = dtoken.Payload.Exp;
            string mobile = rsa.Decrypt(dtoken.Payload.Jti);
            if (exp < new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()) {
                context.Result = new JsonResult(new { code = -14, msg = "登录凭证已过期，请重新登陆" });
                return;
            }

            //string key = Constant.TOKEN_PREFIX + mobile + "_" + loginType;
            var mtoken = await _member.FindAsync<ICasaMielSession>(mobile, 4).ConfigureAwait(false);
            if (mtoken == null) {
                context.Result = new JsonResult(new { code = -18, msg = "登录凭证已过期，请重新登陆" });
                return;
            }
            if (mtoken.Access_Token != token) {
                context.Result = new JsonResult(new { code = -18, msg = "登录凭证已过期，请重新登陆" });
                return;
            }
             
            await next().ConfigureAwait(false);
        }
    }
}
